package xyz.xtt.pay.service.impl;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.pay.api.enums.GoodsTypeEnum;
import xyz.xtt.pay.api.enums.PayOrderStatusEnum;
import xyz.xtt.pay.client.request.BusinessOrderRequest;
import xyz.xtt.pay.client.response.BusinessOrderDto;
import xyz.xtt.pay.client.response.BusinessOrderResponse;
import xyz.xtt.pay.entity.TblBusinessOrder;
import xyz.xtt.pay.mapper.TblBusinessOrderMapper;
import xyz.xtt.pay.service.ITblBusinessOrderService;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author dale
 * @since 2025-02-25
 */
@Slf4j
@Service
public class TblBusinessOrderServiceImpl extends ServiceImpl<TblBusinessOrderMapper, TblBusinessOrder> implements ITblBusinessOrderService {

	@Autowired
	private TblBusinessOrderMapper tblBusinessOrderMapper;

	@Override
	public List<TblBusinessOrder> selectListByGoodsIds(BusinessOrderRequest businessOrderRequest) {
		LambdaQueryWrapper<TblBusinessOrder> queryWrapper = new LambdaQueryWrapper<>();
		if (businessOrderRequest.getGoodsType() != null) {
			queryWrapper.eq(TblBusinessOrder::getGoodsType, businessOrderRequest.getGoodsType());
		}
		if (businessOrderRequest.getGoodsIds() != null && !businessOrderRequest.getGoodsIds().isEmpty()) {
			queryWrapper.in(TblBusinessOrder::getGoodsId, businessOrderRequest.getGoodsIds());
		}
		if (businessOrderRequest.getAppUserId() != null) {
			queryWrapper.eq(TblBusinessOrder::getAppUserId, businessOrderRequest.getAppUserId());
		}
		if (businessOrderRequest.getOrderIds() != null) {
			queryWrapper.in(TblBusinessOrder::getOrderId, businessOrderRequest.getOrderIds());
		}
		queryWrapper
				.in(TblBusinessOrder::getOrderStatus, Arrays
						.asList(PayOrderStatusEnum.UN_PAY.getCode(), PayOrderStatusEnum.PAY_SUCCESS.getCode(), PayOrderStatusEnum.PAY_FAIL
								.getCode(), PayOrderStatusEnum.PAYING.getCode()));
		return tblBusinessOrderMapper.selectList(queryWrapper);
	}

	@Override
	public TblBusinessOrder queryNotPayOrder(long appUserId, GoodsTypeEnum goodsTypeEnum, long goodsId) {
		LambdaQueryChainWrapper<TblBusinessOrder> query = new LambdaQueryChainWrapper<>(baseMapper);
		return query
				.eq(TblBusinessOrder::getAppUserId, appUserId)
				.eq(TblBusinessOrder::getGoodsType, goodsTypeEnum.getCode())
				.eq(TblBusinessOrder::getGoodsId, goodsId)
				.eq(TblBusinessOrder::getOrderStatus, PayOrderStatusEnum.UN_PAY.getCode())
				.one();
	}

	@Override
	public boolean updatePaySuccess(TblBusinessOrder tblBusinessOrder) {
		LocalDateTime now = LocalDateTime.now();
		LambdaUpdateChainWrapper<TblBusinessOrder> update = new LambdaUpdateChainWrapper<>(baseMapper);
		return update
				.eq(TblBusinessOrder::getOrderId, tblBusinessOrder.getOrderId())
				.eq(TblBusinessOrder::getVer, tblBusinessOrder.getVer())
				.in(TblBusinessOrder::getOrderStatus, PayOrderStatusEnum.UN_PAY.getCode(), PayOrderStatusEnum.PAYING.getCode())
				.set(TblBusinessOrder::getOrderStatus, PayOrderStatusEnum.PAY_SUCCESS.getCode())
				.set(TblBusinessOrder::getPaySuccessTime, now)
				.set(TblBusinessOrder::getUpdateTime, now)
				.update();
	}

	@Override
	public boolean updatePayCancel(TblBusinessOrder businessOrder, String reason) {
		LocalDateTime now = LocalDateTime.now();
		LambdaUpdateChainWrapper<TblBusinessOrder> update = new LambdaUpdateChainWrapper<>(baseMapper);
		return update
				.eq(TblBusinessOrder::getOrderId, businessOrder.getOrderId())
				.eq(TblBusinessOrder::getVer, businessOrder.getVer())
				.eq(TblBusinessOrder::getOrderStatus, PayOrderStatusEnum.UN_PAY.getCode())
				.set(TblBusinessOrder::getOrderStatus, PayOrderStatusEnum.PAY_CANCEL.getCode())
				.set(TblBusinessOrder::getCancelTime, now)
				.set(TblBusinessOrder::getCancelReason, reason)
				.set(TblBusinessOrder::getUpdateTime, now)
				.update();
	}

	@Override
	public Map<Long, TblBusinessOrder> getBusinessByIds(Set<Long> ids) {
		if (CollectionUtil.isEmpty(ids)) {
			log.info("ids param:{}", Arrays.asList(ids));
			return Maps.newHashMap();
		}
		List<TblBusinessOrder> list = new LambdaQueryChainWrapper<>(baseMapper).in(TblBusinessOrder::getOrderId, ids).list();
		return list.stream().collect(Collectors.toMap(TblBusinessOrder::getOrderId, item -> item));
	}

	/**
	 * 根据ID查询数据
	 *
	 * @param businessOrderId
	 * @return
	 */
	@Override
	public BusinessOrderDto getBusinessOrderDtoById(Long businessOrderId) {
		TblBusinessOrder businessOrder = new LambdaQueryChainWrapper<>(baseMapper).eq(TblBusinessOrder::getOrderId, businessOrderId).one();
		return convertToDto(businessOrder);
	}

	private BusinessOrderDto convertToDto(TblBusinessOrder businessOrder) {
		BusinessOrderDto dto = new BusinessOrderDto();
		BeanUtils.copyProperties(businessOrder, dto);
		return dto;
	}

	@Override
	public TblBusinessOrder getByIdForUpdate(Long businessOrderId) {
		return new LambdaQueryChainWrapper<>(baseMapper).eq(TblBusinessOrder::getOrderId, businessOrderId).last("for update").one();
	}

	@Override
	public boolean updateOrderPaySuccess(TblBusinessOrder businessOrder) {
		LocalDateTime now = LocalDateTime.now();
		LambdaUpdateChainWrapper<TblBusinessOrder> update = new LambdaUpdateChainWrapper<>(baseMapper);
		return update
				.eq(TblBusinessOrder::getOrderId, businessOrder.getOrderId())
				.in(TblBusinessOrder::getOrderStatus, Arrays.asList(PayOrderStatusEnum.UN_PAY.getCode(), PayOrderStatusEnum.PAYING.getCode()))
				.eq(TblBusinessOrder::getVer, businessOrder.getVer())
				.set(TblBusinessOrder::getOrderStatus, PayOrderStatusEnum.PAY_SUCCESS.getCode())
				.set(TblBusinessOrder::getPaySuccessTime, now)
				.set(TblBusinessOrder::getUpdateTime, now)
				.setIncrBy(TblBusinessOrder::getVer, 1)
				.update();
	}

	@Override
	public boolean updateOrderCancel(TblBusinessOrder businessOrder) {
		LocalDateTime now = LocalDateTime.now();
		LambdaUpdateChainWrapper<TblBusinessOrder> update = new LambdaUpdateChainWrapper<>(baseMapper);
		return update
				.eq(TblBusinessOrder::getOrderId, businessOrder.getOrderId())
				.in(TblBusinessOrder::getOrderStatus, Arrays.asList(PayOrderStatusEnum.UN_PAY.getCode(), PayOrderStatusEnum.PAYING.getCode()))
				.eq(TblBusinessOrder::getVer, businessOrder.getVer())
				.set(TblBusinessOrder::getOrderStatus, PayOrderStatusEnum.PAY_CANCEL.getCode())
				.set(TblBusinessOrder::getUpdateTime, now)
				.setIncrBy(TblBusinessOrder::getVer, 1)
				.update();
	}

	@Override
	public TblBusinessOrder getUnPayBusinessOrder(long buyerId, int code, String goodsId) {
		return lambdaQuery()
				.eq(TblBusinessOrder::getAppUserId, buyerId)
				.eq(TblBusinessOrder::getGoodsType, code)
				.eq(TblBusinessOrder::getGoodsId, goodsId)
				.eq(TblBusinessOrder::getOrderStatus, PayOrderStatusEnum.UN_PAY.getCode())
				.orderByDesc(TblBusinessOrder::getCreateTime)
				.last("limit 1")
				.one();
	}

	@Override
	public BusinessOrderResponse businessOrderInfoWithId(Long businessOrderId) {
		TblBusinessOrder businessOrder = new LambdaQueryChainWrapper<>(baseMapper).eq(TblBusinessOrder::getOrderId, businessOrderId).one();
		BusinessOrderResponse dto = new BusinessOrderResponse();
		BeanUtils.copyProperties(businessOrder, dto);
		return dto;
	}
}
